import wx
import wx.aui
import os.path

from utils.eventHandler import EventHandler, EventArgs
from plugins.base.pane import Pane
from document import Document
from utils import tracer

class DocumentsPane(Pane):
  def __init__(self, parent):
    Pane.__init__(self, parent)
    self._documents = {}
    self._auiNotebook = wx.aui.AuiNotebook(self)

    sizer = wx.BoxSizer()
    sizer.Add(self._auiNotebook, -1, wx.EXPAND)
    self.SetSizer(sizer)
    
    wx.CallAfter(self.Layout)

    self._documentChangedEventHandler = EventHandler()
    self._documentNameChangedEventHandler = EventHandler()

    self._auiNotebook.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.onPageClose)

  # - Interfaces -----------------------------------------------------
  def addDocument(self, filename=''):
    document = self.getDocumentByFilename(filename)
    if document is None:
      document = Document(filename)
      document.setOwner(self)
      if not self._documents.has_key(filename):
        self._documents[filename] = document

      title = os.path.basename(filename)
      if title == '':
        self._auiNotebook.AddPage(document.getEditor(), 'Untitled', True)
      else:
        self._auiNotebook.AddPage(document.getEditor(), title, True)

      # bind document event handlers
      document.getEditor().savePointLeftEventHandler(self.onDocumentSavePointLeft)
      document.getEditor().savePointReachedEventHandler(self.onDocumentSavePointReached)
      document.fileNameChangedEventHandler(self.onFilenameChanged)
      
      tracer.writeln('Added Document: %s' % filename)
    else:
      self.setCurrentDocument(document)

  def removeDocument(self, document):
    if document is None:
      return
    
    fullname = document.getFilename()
    if self._documents.has_key(fullname):
      del self._documents[fullname]

    pageIndex = self._auiNotebook.GetPageIndex(document.getEditor())
    if pageIndex != wx.NOT_FOUND:
      self._auiNotebook.RemovePage(pageIndex)

    editor = document.getEditor()
    if not editor is None:
      editor.Hide()

    document.setOwner(None)
    tracer.writeln('Deleted document: %s' % fullname)

  def newDocument(self):
    self.addDocument()

  def openDocument(self, filename=''):
    if filename == '':
      wildcard = "Python source (*.py)|*.py|"     \
               "All files (*.*)|*.*"
    
      dlg = wx.FileDialog(None, message='Choose a file',
                                 defaultDir = os.getcwd(),
                                 defaultFile='',
                                 wildcard=wildcard,
                                 style=wx.OPEN | wx.CHANGE_DIR | wx.MULTIPLE)

      if dlg.ShowModal() == wx.ID_OK:
        paths = dlg.GetPaths()
        for path in paths:
          try:
            self.addDocument(path)
          except:
            errDlg = wx.MessageDialog(self, 'Can not open file: %s' % path,
                                          'Error', wx.OK | wx.ICON_ERROR)
            errDlg.ShowModal()
            errDlg.Destroy()
          finally:
            dlg.Destroy()
        dlg.Destroy()
    else:
      self.addDocument(filename)

  def saveDocument(self, document=None):
    curDoc = document
    if curDoc is None:
      curDoc = self.getCurrentDocument()      
      if curDoc is None:
        return False

    if curDoc.getFilename() == '':
      return self.saveDocumentAs('', curDoc)
    return curDoc.saveFile()

  def saveDocumentAs(self, filename, document=None):
    curDoc = document
    if curDoc is None:
      curDoc = self.getCurrentDocument()
      if curDoc is None:
        return False

    if filename == '':
      wildcard = "Python source (*.py)|*.py|"     \
               "All files (*.*)|*.*"
    
      dlg = wx.FileDialog(None, message='Save file as ...',
                                 defaultDir = os.getcwd(),
                                 defaultFile='',
                                 wildcard=wildcard,
                                 style=wx.SAVE | wx.CHANGE_DIR)

      if dlg.ShowModal() == wx.ID_OK:
        filename = dlg.GetPath()
      
    curDoc.setFilename(filename)
    return curDoc.saveFile()

  def saveAll(self):
    for doc in self._documents.values():
      editor = doc.getEditor()
      if editor is None:
        continue
      if editor.getModify():
        self.saveDocument(doc)

  def closeDocument(self, document=None):    
    curDoc = document
    if curDoc is None:
      curDoc = self.getCurrentDocument()
      if curDoc is None:
        return

    editor = curDoc.getEditor()
    tracer.writeln('Close File: %s' % curDoc.getFilename())

    if not editor is None and editor.getModify():
      tracer.writeln('File %s had been modified.' % curDoc.getFilename())
      if wx.MessageDialog(self, 'Do you want to save file: %s' % curDoc.getFilename(),
                             'Warning', wx.YES | wx.NO | wx.ICON_WARNING).ShowModal() == wx.ID_YES:
        self.saveDocument(curDoc)

    self.removeDocument(curDoc)

  def closeAll(self):
    for doc in self._documents.values():
      self.closeDocument(doc)

  def gotoDocumentLine(self, lineNo, document=None):    
    curDoc = document
    if curDoc is None:
      curDoc = self.getCurrentDocument()
      if curDoc is None:
        return
    else:
      self.setCurrentDocument(curDoc)

    editor = curDoc.getEditor()
    if editor is None:
      return
    editor.setCurLine(lineNo)
      
  def getDocumentByFilename(self, filename):
    tracer.writeln('Get Document: %s' % filename)
    if self._documents.has_key(filename):
      tracer.writeln('  File found.')
      return self._documents[filename]
    tracer.writeln('  File not found.')
    return None

  def getCurrentDocument(self):
    curPageIndex = self._auiNotebook.GetSelection()
    if curPageIndex == -1:
      return None

    curPage = self._auiNotebook.GetPage(curPageIndex)
    return self.getDocumentByPage(curPage)

  def setCurrentDocument(self, document):
    pageIndex = self._auiNotebook.GetPageIndex(document.getEditor())
    if pageIndex != wx.NOT_FOUND:
      self._auiNotebook.SetSelection(pageIndex)
      
  # - Local methods ------------------------------------------------------
  def getConfigFileName(self):
    return os.path.dirname(__file__) + os.path.sep + 'config.cfg'
  
  def getDocumentByPage(self, page):
    for doc in self._documents.values():
      if doc.getEditor() == page:
        return doc
    return None

  def setPageText(self, document, text_prefix):
    page = document.getEditor()
    if page is None:
      return

    pageIndex = self._auiNotebook.GetPageIndex(page)
    if pageIndex == wx.NOT_FOUND:
      return

    filename = document.getFilename()
    if filename == '':
      filename = 'Untitle'
    title = '%s%s' % (text_prefix, os.path.basename(filename))
    self._auiNotebook.SetPageText(pageIndex, title)

  # -- Event Handlers -----------------------------------------------------
  def documentChangedEventHandler(self, handler):
    self._documentChangedEventHandler.add(handler)
  def onDocumentChanged(self, document):
    eventArgs = EventArgs((document,))
    self._documentChangedEventHandler.invoke(self, eventArgs)

  def documentNameChangedEventHandler(self, handler):
    self._documentNameChangedEventHandler.add(handler)
  def onDocumentNameChanged(self, document):
    eventArgs = EventArgs((document,))
    self._documentNameChangedEventHandler.invoke(self, eventArgs)
  
  # -- Events -------------------------------------------------------------
  def onPageClose(self, evt):
    selectIndex = evt.GetSelection()
    if selectIndex >= 0:
      page = self._auiNotebook.GetPage(selectIndex)
      if not page is None:
        document = self.getDocumentByPage(page)
        if not document is None:
          self.closeDocument(document)

  def onDocumentSavePointLeft(self, sender, args):
    self.setPageText(args.getValue()[0], '*')
    
  def onDocumentSavePointReached(self, sender, args):
    self.setPageText(args.getValue()[0], '')
    self.onDocumentChanged(args.getValue()[0])

  def onFilenameChanged(self, sender, args):
    oldname, newname = args.getValue()

    if self._documents.has_key(oldname):
      del self._documents[oldname]
    if not self._documents.has_key(newname):
      self._documents[newname] = sender
    
    self.setPageText(sender, newname)
    self.onDocumentNameChanged(sender)
